/**
 * Copyright (c) 快宝网络 kuaidihelp.com Co., Ltd. All Rights Reserved 禁止外泄以及用于其它的商业用途
 */

/* eslint-disable no-use-before-define */
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable consistent-return */
import React, { Fragment } from 'react';
import { Layout, Icon, Spin } from 'antd';
import DocumentTitle from 'react-document-title';
import { connect } from 'dva';
import routerRedux from 'umi/router';
import { ContainerQuery } from 'react-container-query';
import classNames from 'classnames';
import pathToRegexp from 'path-to-regexp';
import { enquireScreen, unenquireScreen } from 'enquire-js';
import memoizeOne from 'memoize-one';
import isEqual from 'lodash/isEqual';
import GlobalHeader from '@/components/GlobalHeader';
import GlobalFooter from '@/components/GlobalFooter';
import SiderMenu from '@/components/SiderMenu';
import Authorized from '@/utils/Authorized';
import AuthorizedNoMatch, { checkAuthority } from '@/utils/authority';
import Link from 'umi/link';
import Redirect from 'umi/redirect';
import styles from './BasicLayout.less';
import Context from './MenuContext';
import { fixMenusByHost } from '@/utils/layout';

const { Content, Header, Footer } = Layout;
const { MODE_ENV } = process.env;
// 是否是自动化本地服务器
const isAutomaticLocal = MODE_ENV === 'AUTOMATIC';

// Conversion router to menu.
function formatter(data, parentAuthority) {
  return data
    .map(item => {
      if (!item.name || !item.path) {
        return null;
      }

      const result = {
        ...item,
        authority: item.authority || parentAuthority || '',
      };
      if (item.routes) {
        const children = formatter(item.routes, item.authority);
        // Reduce memory usage
        result.children = children;
      }
      delete result.routes;
      return result;
    })
    .filter(item => item);
}

const memoizeOneFormatter = memoizeOne(formatter, isEqual);
const query = {
  'screen-xs': {
    maxWidth: 575,
  },
  'screen-sm': {
    minWidth: 576,
    maxWidth: 767,
  },
  'screen-md': {
    minWidth: 768,
    maxWidth: 991,
  },
  'screen-lg': {
    minWidth: 992,
    maxWidth: 1199,
  },
  'screen-xl': {
    minWidth: 1200,
    maxWidth: 1599,
  },
  'screen-xxl': {
    minWidth: 1600,
  },
};

let isMobile;
enquireScreen(b => {
  isMobile = b;
});

@connect(({ user, global, setting, info, loading }) => ({
  currentUser: user.currentUser,
  collapsed: global.collapsed,
  authority: global.authority,
  layout: setting.layout,
  info: info.getInfo,
  info_getting: loading.effects['info/getInfo'],
  companyData: info.companyData,
  ...setting,
}))
export default class BasicLayout extends React.PureComponent {
  constructor(props) {
    super(props);
    this.getPageTitle = memoizeOne(this.getPageTitle);
    this.getBreadcrumbNameMap = memoizeOne(this.getBreadcrumbNameMap, isEqual);
    this.breadcrumbNameMap = this.getBreadcrumbNameMap();
    this.matchParamsPath = memoizeOne(this.matchParamsPath, isEqual);
  }

  state = {
    isMobile,
    menuData: this.getMenuData(),
    firstAuthoritiedPath: '',
  };

  componentDidMount() {
    const { dispatch } = this.props;

    // 自动化本地访问，无需请求info接口
    if (!isAutomaticLocal) {
      dispatch({
        type: 'info/getInfo',
      });
    }

    this.enquireHandler = enquireScreen(mobile => {
      this.setState({
        isMobile: mobile,
      });
    });
  }

  componentDidUpdate(prevProps, prevState) {
    const { firstAuthoritiedPath } = this.state;
    const { firstAuthoritiedPath: _firstAuthoritiedPath } = prevState;
    if (firstAuthoritiedPath === _firstAuthoritiedPath && !_firstAuthoritiedPath) {
      this.setFirstAuthoritiedPath();
      // eslint-disable-next-line react/no-did-update-set-state
      this.setState({
        menuData: this.getMenuData(),
      });
    }
  }

  componentWillUnmount() {
    unenquireScreen(this.enquireHandler);
  }

  getContext() {
    const {
      location,
      options: { key, subKey },
    } = this.props;

    const isZyAccount = key === 'post';
    const isTongDi = subKey === 'td';
    const { firstAuthoritiedPath } = this.state;
    return {
      location,
      breadcrumbNameMap: this.breadcrumbNameMap,
      firstAuthoritiedPath,
      isZyAccount,
      isTongDi,
    };
  }

  getMenuData() {
    const {
      route: { routes },
      options,
      currentUser: { user_info: { realAccount, area_ids, gp_area_ids = [] } = {} } = {},
    } = this.props;
    // 真假账号
    const menuDate = memoizeOneFormatter(routes);

    const fakeAccount = realAccount == 2;

    fixMenusByHost(menuDate, { ...options, fakeAccount, realAccount, area_ids, gp_area_ids });

    return menuDate;
  }

  getHeadWidth = () => {
    const { collapsed } = this.props;
    if (isMobile) {
      return '100%';
    }
    return collapsed ? 'calc(100% - 80px)' : 'calc(100% - 256px)';
  };

  getLayoutStyle = () => {
    const { fixSiderbar, collapsed, layout } = this.props;
    if (isMobile) {
      return {
        paddingLeft: 0,
      };
    }
    if (fixSiderbar && layout !== 'topmenu') {
      return {
        paddingLeft: collapsed ? '80px' : '256px',
      };
    }
    return null;
  };

  getContentStyle = () => {
    const { fixedHeader } = this.props;
    return {
      margin: '24px 24px 0',
      paddingTop: fixedHeader ? 64 : 0,
    };
  };

  /**
   * 获取面包屑映射
   * @param {Object} menuData 菜单配置
   */
  getBreadcrumbNameMap() {
    const routerMap = {};
    const mergeMenuAndRouter = data => {
      data.forEach(menuItem => {
        if (menuItem.children) {
          mergeMenuAndRouter(menuItem.children);
        }
        // Reduce memory usage
        routerMap[menuItem.path] = menuItem;
      });
    };
    mergeMenuAndRouter(this.getMenuData());
    return routerMap;
  }

  getPageTitle(pathname) {
    const {
      options: { key, subKey },
    } = this.props;
    const titleMap = {
      yz: '快宝智慧快递管理平台-快递末端企业专用管理系统',
      post: '中邮共配管理系统',
      yjy: '驿加易共配管理系统',
      td: '智慧快递管理平台',
    };
    const currRouterData = this.matchParamsPath(pathname);
    if (!currRouterData) return titleMap[subKey || key];
    return `${currRouterData.name} - ${titleMap[subKey || key]}`;
  }

  // 设置第一个有效的路径，供广告位使用
  setFirstAuthoritiedPath() {
    const { menuData } = this.state;
    const { authority } = this.props;
    const list = menuData
      .filter(item => this.checkAuthority(authority, item))
      .map(({ children, ...rest }) => ({
        ...rest,
        children:
          children && children.length > 0
            ? children.filter(iitem => this.checkAuthority(authority, iitem))
            : undefined,
      }));
    if (list.length > 0) {
      this.setState({
        firstAuthoritiedPath: list[0].children ? list[0].children[0].path : list[0].path,
      });
    }
  }

  matchParamsPath = pathname => {
    const pathKey = Object.keys(this.breadcrumbNameMap).find(key =>
      pathToRegexp(key).test(pathname),
    );
    return this.breadcrumbNameMap[pathKey];
  };

  handleMenuCollapse = collapsed => {
    const { dispatch } = this.props;
    dispatch({
      type: 'global/changeLayoutCollapsed',
      payload: collapsed,
    });
  };

  handleMenuClick = ({ key }) => {
    const { dispatch } = this.props;
    if (key === 'logout') {
      dispatch({
        type: 'login/logout',
        payload: {
          run: '/Auth/logout',
          time: Date.now()
            .toString()
            .substring(0, 10),
          data: '',
        },
      });
    } else if (key === 'info') {
      routerRedux.push({
        pathname: '/system/info',
      });
    }
  };

  // 根据路由authority配置检测路由权限
  checkAuthority = (
    currentAuthority,
    currentRouter = this.matchParamsPath(this.props.location.pathname),
    opts,
  ) => {
    const {
      options: { hideWhileNoAuth = [] },
    } = this.props;
    return checkAuthority(currentAuthority, currentRouter, opts, hideWhileNoAuth);
  };

  // 获取可跳转的有效路径
  matchRedirectPath = () => {
    const { menuData } = this.state;
    const {
      authority,
      currentUser,
      options: { key },
    } = this.props;
    const isZyAccount = key === 'post';
    const isZJ = currentUser && currentUser.user_info && currentUser.user_info.branchLevel == 4;

    if (isZyAccount && authority) {
      const { root = [] } = authority;
      menuData.forEach(i => {
        if (i.path == '/Allocation') {
          if (isZJ || !root.includes('allocation')) {
            // 支局或者没有共配权限的账号需要，屏蔽中邮驿路菜单
            i.hideInMenu = true;
          }
        }
      });
    }

    if (!this.checkAuthority(authority, undefined, true)) {
      // 当前路由不可用，返回可用路由
      const list = menuData
        .filter(item => this.checkAuthority(authority, item))
        .map(({ children, ...rest }) => ({
          ...rest,
          children:
            children && children.length > 0
              ? children.filter(iitem => this.checkAuthority(authority, iitem))
              : undefined,
        }));
      const listItem = list[0];
      if (!listItem) return;
      const listHasChildren = list.filter(item => item.children);
      if (listHasChildren.length > 0) {
        return listHasChildren[0].children[0].path;
      }
      return listItem.path;
    }
  };

  render() {
    const {
      currentUser,
      collapsed,
      fetchingNotices,
      notices,
      fixedHeader,
      navTheme,
      children,
      info_getting,
      companyData,
      location,
      options, // 全局配置
    } = this.props;
    const { pathname } = location;
    const { logo, recordNo, copyright } = options;
    const { isMobile: mb, menuData } = this.state;
    const matchedRedirectPath = this.matchRedirectPath();
    const year = new Date().getFullYear();
    const layout = (
      <Layout>
        <SiderMenu
          logo={logo}
          theme={navTheme}
          // 不带Authorized参数的情况下如果没有权限,会强制跳到403界面,自动化本地页面需屏蔽权限校验
          Authorized={!isAutomaticLocal ? Authorized : null}
          checkAuthority={this.checkAuthority}
          menuData={menuData}
          collapsed={collapsed}
          location={location}
          isMobile={mb}
          onCollapse={this.handleMenuCollapse}
        />
        <Layout
          style={{
            ...this.getLayoutStyle(),
            minHeight: '100vh',
          }}
        >
          <Header
            style={{ padding: 0, width: this.getHeadWidth() }}
            className={fixedHeader ? styles.fixedHeader : ''}
          >
            <GlobalHeader
              logo={logo}
              currentUser={currentUser}
              fetchingNotices={fetchingNotices}
              notices={notices}
              collapsed={collapsed}
              isMobile={mb}
              onCollapse={this.handleMenuCollapse}
              onMenuClick={this.handleMenuClick}
              companyData={companyData}
            />
          </Header>
          <Spin spinning={!!info_getting}>
            <Layout>
              <Content style={this.getContentStyle()}>
                {isAutomaticLocal
                  ? children
                  : !info_getting && (
                      <Authorized
                        authority={this.checkAuthority}
                        linkElement={Link}
                        noMatch={
                          matchedRedirectPath ? (
                            <Redirect to={matchedRedirectPath} />
                          ) : (
                            <AuthorizedNoMatch />
                          )
                        }
                      >
                        {children}
                      </Authorized>
                    )}
              </Content>
              <Footer style={{ padding: 0 }}>
                <GlobalFooter
                  links={[]}
                  copyright={
                    <Fragment>
                      Copyright <Icon type="copyright" /> {year} {copyright}
                    </Fragment>
                  }
                  recordNo={recordNo}
                />
              </Footer>
            </Layout>
          </Spin>
        </Layout>
      </Layout>
    );

    return (
      <DocumentTitle title={this.getPageTitle(pathname)}>
        <ContainerQuery query={query}>
          {params => (
            <Context.Provider value={this.getContext()}>
              <div className={classNames(params)}>{layout}</div>
            </Context.Provider>
          )}
        </ContainerQuery>
      </DocumentTitle>
    );
  }
}
